package com.jourwon.spring.boot.controller;

import com.alibaba.fastjson.JSONObject;
import com.jourwon.spring.boot.model.entity.User;
import com.jourwon.spring.boot.validator.AddGroup;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * json请求
 *
 * @author JourWon
 * @date 2022/1/18
 */
@Slf4j
@Api(tags = "json请求")
@RestController
@RequestMapping("/json")
public class JsonController {

    @Resource
    private Validator validator;

    /**
     * 后端用实体类进行接收
     * 前端则调用url：localhost:8080/json/postByUser
     * <p>
     * 1.时间类型字段createTime不加@JsonFormat(locale = "zh", timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")会报错
     * HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.time.LocalDateTime` from String "2022-01-01 00:00:00"
     * 也可以通过增加日期转换配置类处理此类错误
     * <p>
     * 2.integer类型字段用"18"字符串数字可以正常接收，但是如果用"abc"字符串则会报错
     * HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.lang.Integer` from String "abc"
     * <p>
     * 3.如果后端已经使用了@RequestBody注解，代表只接收application/json类型的数据，
     * 此时若再传入application/x-www-form-urlencoded类型的数据，则后台会报错HttpMediaTypeNotSupportedException
     *
     * @param user
     * @return
     */
    @PostMapping("/postByUser")
    @ApiOperation("后端用实体类进行接收")
    public User postByUser(@RequestBody @Validated User user) {
        return user;
    }

    @PostMapping("/postByUserValidtor")
    @ApiOperation("后端用实体类进行接收,手动校验")
    public User postByUserValidtor(@RequestBody User user) {
        // 验证所有bean的所有约束
        Set<ConstraintViolation<User>> constraintViolations = validator.validate(user);
        // 验证单个属性
        Set<ConstraintViolation<User>> constraintViolations2 = validator.validateProperty(user, "username");
        // 检查给定类的单个属性是否可以成功验证
        Set<ConstraintViolation<User>> constraintViolations3 = validator.validateValue(User.class, "password", "sa!");

        constraintViolations.forEach(constraintViolation -> System.out.println(constraintViolation.getMessage()));
        constraintViolations2.forEach(constraintViolation -> System.out.println(constraintViolation.getMessage()));
        constraintViolations3.forEach(constraintViolation -> System.out.println(constraintViolation.getMessage()));

        return user;
    }

    @PostMapping("/postByUserAddGroup")
    @ApiOperation("后端用实体类进行接收,分组检验")
    public User postByUserAddGroup(@RequestBody @Validated(AddGroup.class) User user) {
        return user;
    }

    @PostMapping("/postByUserRecursion")
    @ApiOperation("后端用实体类进行接收,递归校验")
    public User postByUserRecursion(@RequestBody @Validated User user) {
        return user;
    }

    /**
     * 后端用实体类进行接收
     * 可以在参数添加@Validated进行参数校验
     *
     * @param user
     * @return
     */
    @PostMapping("/formByUser")
    @ApiOperation("表单请求,后端用实体类进行接收")
    public User formByUser(@Validated User user) {
        return user;
    }

    /**
     * 后端用参数进行接收
     *
     * @param name
     * @param age
     * @return
     */
    @PostMapping("/formByParam")
    @ApiOperation("表单请求,后端用参数进行接收")
    public User loginByParam(@RequestParam("name1") String name,
                             @RequestParam(value = "age", required = true) int age) {
        return new User(name, age);
    }

    /**
     * 后端用Map来接收
     *
     * @param map
     * @return
     */
    @PostMapping("/formByMap")
    @ApiOperation("表单请求,后端用Map来接收")
    public User formByMap(@RequestParam Map<String, Object> map) {
        String name = (String) map.get("name");
        int age = Integer.parseInt((String) map.get("age"));
        return new User(name, age);
    }

    /**
     * 后端用Map来接收
     *
     * @param map
     * @return
     */
    @PostMapping("/jsonByMap")
    @ApiOperation("后端用Map来接收")
    public User jsonByMap(@RequestBody Map<String, Object> map) {
        String name = (String) map.get("name");
        int age = (Integer) map.get("age");
        return new User(name, age);
    }

    /**
     * 后端用JSONObject来接收
     *
     * @param jsonObject
     * @return
     */
    @PostMapping("/jsonObject")
    @ApiOperation("后端用JSONObject来接收")
    public User jsonObject(@RequestBody JSONObject jsonObject) {
        String name = jsonObject.getString("username");
        int age = jsonObject.getInteger("age");
        return new User(name, age);
    }

    /**
     * 后端用数组来接收
     *
     * @param a
     * @return
     */
    @PostMapping("/array")
    @ApiOperation("后端用数组来接收")
    public Integer[] array(Integer[] a) {
        return a;
    }

    /**
     * 后端用列表接收
     *
     * @param a
     * @return
     */
    @PostMapping("/list")
    @ApiOperation("后端用列表接收")
    public List<Integer> list(@RequestParam("a") List<Integer> a) {
        return a;
    }


}
